package com.yangxc.core.aspect.exception;

import com.sun.corba.se.impl.io.TypeMismatchException;
import com.yangxc.core.common.api.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.support.MissingServletRequestPartException;

import javax.validation.ConstraintViolationException;
import java.nio.file.AccessDeniedException;
import java.util.stream.Collectors;

/**
 * @author yangxc
 * @version 1.0.0
 * @ClassName GlobalBizExceptionHandler.java
 * @Description TODO 全局异常
 * @createTime 2022年10月13日 11:13:00
 */
@Slf4j
@RestController
@RestControllerAdvice
public class GlobalBizExceptionHandler {
    
    /**
     * 全局异常.
     * @param e the e
     * @return R
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result handleGlobalException(Exception e) {
        log.error("全局异常信息 ex={}", e.getMessage(), e);
        log.error("异常详细:{}",e.getLocalizedMessage());
        return Result.fail("系统异常，请联系客服");
    }
    
    /**
     * AccessDeniedException
     * @param e the e
     * @return R
     */
    @ExceptionHandler(AccessDeniedException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public Result handleAccessDeniedException(AccessDeniedException e) {
        log.error("拒绝授权异常信息 ex={}", e.getMessage());
        return Result.fail("授权失败");
    }
    
    
    /**
     * 避免 404 重定向到 /error 导致NPE ,ignore-url 需要配置对应端点
     * @return R
     */
    @DeleteMapping("/error")
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Result noHandlerFoundException() {
        return Result.fail("页面未找到");
    }
    
    
    /**
     * 处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是javax.validation.ConstraintViolationException
     * @param exception
     * @return
     */
    @ExceptionHandler({ ConstraintViolationException.class })
    @ResponseStatus(HttpStatus.OK)
    public Result handleConstraintViolationException(ConstraintViolationException exception) {
        String message = exception.getConstraintViolations().stream()
                .map(constraintViolation ->
                        String.format("【%s】输入错误，%s",constraintViolation.getInvalidValue()
                                ,constraintViolation.getMessage())).collect(Collectors.joining(";"));
        log.warn("参数绑定异常【ConstraintViolationException】,ex = {}", message);
        return Result.fail(message);
    }
    
    /**
     * @requestbody 参数错误校验
     * @param exception
     * @return
     */
    @ExceptionHandler({ BindException.class })
    @ResponseStatus(HttpStatus.OK)
    public Result handleBindException(BindException exception) {
        BindingResult bindingResult = exception.getBindingResult();
        if (bindingResult != null) {
            //收集所有错误信息
            String message = bindingResult.getFieldErrors().stream()
                    //.map(s -> String.format("参数【%s】输入错误，%s",s.getRejectedValue(),s.getDefaultMessage()) ).collect(Collectors.joining(";"));
                    .map(s -> s.getDefaultMessage() ).collect(Collectors.joining(";"));
            log.warn("参数绑定异常,ex = {}", message);
            return Result.fail(message);
        }
        return Result.fail("参数错误");
    }
    
    /**
     * 参数缺失
     * @param exception
     * @return
     */
    @ExceptionHandler({MissingServletRequestParameterException.class})
    @ResponseStatus(HttpStatus.OK)
    public Result handleMissingServletRequestParameterException(MissingServletRequestParameterException exception) {
        log.error("MissingServletRequestParameterException异常，ex={}" , exception);
        return Result.fail(String.format("参数：%s 缺失", exception.getParameterName()));
    }
    
    @ExceptionHandler({MissingServletRequestPartException.class})
    @ResponseStatus(HttpStatus.OK)
    public Result handleMissingServletRequestParameterException(MissingServletRequestPartException exception) {
        log.error("MissingServletRequestParameterException异常，ex={}" , exception);
        return Result.fail(String.format("参数：%s 缺失", exception.getRequestPartName()));
    }
    
    /**
     * 参数非法
     * @param exception
     * @return
     */
    @ExceptionHandler({IllegalArgumentException.class, TypeMismatchException.class, HttpMessageNotReadableException.class})
    @ResponseStatus(HttpStatus.OK)
    public Result handleIllegalArgumentException(RuntimeException exception) {
        log.error("参数非法异常，ex={}" , exception);
        return Result.fail("参数非法");
    }
    
    
    
    /**
     * 自定义异常
     * @param exception
     * @return
     */
    @ExceptionHandler({AbstractException.class})
    @ResponseStatus(HttpStatus.OK)
    public Result handleConstraintViolationException(AbstractException exception) {
        log.warn("AbstractException自定义异常，错误信息={}" , exception.getMessage());
        return Result.fail(exception.getMessage());
    }
    
    
    /**
     * 空指针异常
     * @param exception
     * @return
     */
    @ExceptionHandler({NullPointerException.class})
    @ResponseStatus(HttpStatus.OK)
    public Result handleNullPointerException(NullPointerException exception) {
        log.error("NullPointerException异常，ex={}" , exception);
        return Result.fail("系统空指针，联系管理员");
    }
    
    /**
     * 请求方式异常
     * @param exception
     * @return
     */
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    @ResponseStatus(HttpStatus.OK)
    public Result handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException exception) {
        log.error("HttpRequestMethodNotSupportedException异常，ex={}" , exception);
        return Result.fail(String.format("请求方式: %s无效",exception.getMethod()));
    }
    
}
